package com.pai4j.message.websocket;

import com.pai4j.common.util.JsonUtil;
import com.pai4j.message.core.sender.AbstractMessageSender;
import com.pai4j.message.model.MessageContext;
import com.pai4j.message.model.SendResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import jakarta.annotation.PostConstruct;
import java.util.Set;

/**
 * WebSocket消息发送器
 * 通过WebSocket实时推送消息到在线用户
 * 
 * 支持多端推送（PC、Mobile等）
 *
 * @author PAI4J Team
 * @date 2025-11-01
 */
@Slf4j
@Component
public class WebSocketMessageSender extends AbstractMessageSender {

    @Autowired
    private WebSocketSessionManager sessionManager;

    @Autowired(required = false)
    private WebSocketProperties webSocketProperties;

    @PostConstruct
    public void register() {
        com.pai4j.message.factory.MessageSenderFactory.register(this);
        log.info("WebSocketMessageSender已注册");
    }

    @Override
    public String getChannel() {
        return "websocket";
    }

    @Override
    protected SendResult doSend(MessageContext context) {
        if (!validateContext(context)) {
            return SendResult.failure("INVALID_CONTEXT", "消息上下文验证失败", getChannel());
        }

        String receiverId = context.getReceiverId();
        String messageId = generateMessageId();
        
        // 转换消息为JSON格式
        String jsonMessage = JsonUtil.toJsonString(context);
        if (jsonMessage == null) {
            return SendResult.failure("CONVERT_ERROR", "消息转换失败", getChannel());
        }

        // 获取需要推送的业务代码列表
        Set<String> bizCodes = getBizCodes();
        boolean pushed = false;
        int successCount = 0;
        
        try {
            for (String bizCode : bizCodes) {
                WebSocketSession session = sessionManager.getSession(bizCode, receiverId);
                if (session != null && session.isOpen()) {
                    try {
                        session.sendMessage(new TextMessage(jsonMessage));
                        log.info("WebSocket消息发送成功 => bizCode:{}, userId:{}, messageId:{}", 
                                bizCode, receiverId, messageId);
                        pushed = true;
                        successCount++;
                    } catch (Exception e) {
                        log.warn("WebSocket消息发送失败 => bizCode:{}, userId:{}, error:{}", 
                                bizCode, receiverId, e.getMessage());
                    }
                }
            }

            if (pushed) {
                return SendResult.success(messageId, getChannel())
                        .addExtData("bizCodes", bizCodes)
                        .addExtData("successCount", successCount);
            } else {
                return SendResult.failure("USER_OFFLINE", "用户不在线", getChannel())
                        .addExtData("receiverId", receiverId);
            }

        } catch (Exception e) {
            log.error("WebSocket消息发送异常：{}", e.getMessage(), e);
            return SendResult.failure("SEND_ERROR", e.getMessage(), getChannel());
        }
    }

    /**
     * 获取配置的业务代码列表
     * 如果未配置，返回所有已连接的业务代码
     *
     * @return 业务代码集合
     */
    private Set<String> getBizCodes() {
        if (webSocketProperties != null && webSocketProperties.getBizCodes() != null 
                && !webSocketProperties.getBizCodes().isEmpty()) {
            return webSocketProperties.getBizCodes();
        }
        
        // 如果未配置，返回所有已连接的业务代码
        Set<String> allBizCodes = sessionManager.getAllBizCodes();
        if (!allBizCodes.isEmpty()) {
            return allBizCodes;
        }
        
        // 默认业务代码
        return Set.of("PC_CHAT", "MOBILE_CHAT", "WEB_CHAT");
    }

    @Override
    public boolean isAvailable() {
        return sessionManager != null ;
    }

    @Override
    public int getPriority() {
        return 8; // 优先级稍低于MQ
    }

    @Override
    protected boolean isRetryable(SendResult result) {
        // WebSocket发送失败通常不重试（用户离线或网络问题）
        return false;
    }

    /**
     * 向指定用户推送消息（所有在线端）
     *
     * @param userId 用户ID
     * @param message 消息内容
     * @return 成功推送的端数量
     */
    public int pushToUser(String userId, String message) {
        if (userId == null || message == null) {
            return 0;
        }

        int successCount = 0;
        Set<String> bizCodes = getBizCodes();

        for (String bizCode : bizCodes) {
            WebSocketSession session = sessionManager.getSession(bizCode, userId);
            if (session != null && session.isOpen()) {
                try {
                    session.sendMessage(new TextMessage(message));
                    successCount++;
                } catch (Exception e) {
                    log.warn("推送消息失败 => bizCode:{}, userId:{}, error:{}", bizCode, userId, e.getMessage());
                }
            }
        }

        return successCount;
    }

    /**
     * 向指定用户的指定端推送消息
     *
     * @param bizCode 业务代码
     * @param userId 用户ID
     * @param message 消息内容
     * @return 是否发送成功
     */
    public boolean pushToUserOnBizCode(String bizCode, String userId, String message) {
        if (bizCode == null || userId == null || message == null) {
            return false;
        }

        WebSocketSession session = sessionManager.getSession(bizCode, userId);
        if (session != null && session.isOpen()) {
            try {
                session.sendMessage(new TextMessage(message));
                return true;
            } catch (Exception e) {
                log.warn("推送消息失败 => bizCode:{}, userId:{}, error:{}", bizCode, userId, e.getMessage());
                return false;
            }
        }

        return false;
    }
}

